package solution1.demo1201.demo2;

import solution1.demo1201.demo2.request.LoginArguments;
import solution1.demo1201.demo2.request.LoginResponse;
import solution1.demo1201.demo2.request.Request;
import solution1.demo1201.demo2.request.Response;
import solution1.demo1201.demo2.tool.BinaryTool;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TCPServer {

    private ServerSocket serverSocket;
    private ExecutorService pool;

    public TCPServer(int port) throws IOException {
        this.serverSocket = new ServerSocket(port);
    }

    public void start() {
        System.out.println("[TCPServer] 启动！");
        pool = Executors.newCachedThreadPool();
        pool.submit(() -> {
            try {
                Socket clientSocket = serverSocket.accept();
                clientProcess(clientSocket);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }

    /**
     * 读取请求
     */
    public Request readRequest(DataInputStream dataInputStream) throws IOException {
        Request request = new Request();
        request.setType(dataInputStream.readInt());
        request.setLength(dataInputStream.readInt());
        byte[] payload = new byte[request.getLength()];
        int read = dataInputStream.read(payload);
        request.setBody(payload);
        if(read != request.getLength()) {
            throw new RuntimeException("[TCPServer] 解析请求格式出错");
        }
        return request;
    }

    public void writeResponse(DataOutputStream dataOutputStream, Response response) throws IOException {
        dataOutputStream.writeInt(response.getType());
        dataOutputStream.writeInt(response.getLength());
        dataOutputStream.write(response.getBody());
        dataOutputStream.flush();
    }

    private void clientProcess(Socket clientSocket) throws IOException {
        System.out.println("[TCPServer] 客户端上线！ ip: " + clientSocket.getInetAddress() + ", port: " + clientSocket.getPort());
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()) {
            try(DataInputStream dataInputStream = new DataInputStream(inputStream);
                DataOutputStream dataOutputStream = new DataOutputStream(outputStream);) {
                while(true) {
                    //1.接收客户端请求
                    Request request = readRequest(dataInputStream);
                    //2.服务器根据请求计算响应
                    LoginArguments arguments = (LoginArguments) BinaryTool.fromBytes(request.getBody());
                    System.out.println("[TCPServer] 收到客户端请求！data=" + arguments);
                    Response response = new Response();
                    if(request.getType() == 0x1) {
                        LoginResponse loginResponse = new LoginResponse();
                        loginResponse.setType(0x1);
                        loginResponse.setOk(true);
                        byte[] payload = BinaryTool.toBytes(loginResponse);
                        response.setType(0x1);
                        response.setLength(payload.length);
                        response.setBody(payload);
                    }
                    //3.返回服务器响应
                    writeResponse(dataOutputStream, response);
                }
            }
        } catch (EOFException | SocketException e) {
            System.out.println("[TCPServer] 客户端下线！ ip: " + clientSocket.getInetAddress() + ", port: " + clientSocket.getPort());
        } finally {
            clientSocket.close();
        }
    }

    public static void main(String[] args) throws IOException {
        TCPServer tcpServer = new TCPServer(9090);
        tcpServer.start();
    }

}
